/*
 * MIT License
 *
 * Copyright (c) 2024-2048 冰羽
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package cn.star.framework.excel.enhance;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.star.framework.excel.annotation.Convert;
import cn.star.framework.excel.convert.CellValueConverter;
import cn.star.framework.excel.convert.CellValueValidateRule;
import cn.star.framework.excel.core.Column;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 将类转换为{@link Column}集合<br>
 *
 * @author zhaoweiping
 *     <p style='color: red'>Created on 2024-09-23 11:06:00
 * @since 3.0.0
 */
public final class ClassColumnConverter {
  public static final ClassColumnConverter INSTANCE = new ClassColumnConverter();

  private ClassColumnConverter() {}

  public List<Column> convert(Class<?> clazz) {
    return this.initColumns(clazz);
  }

  private List<Column> initColumns(Class<?> clazz) {
    final List<Column> columns = new ArrayList<>();
    Field[] fields = ReflectUtil.getFields(clazz);
    for (Field field : fields) {
      // # issue 20230925 静态字段不允许导出
      int modifiers = field.getModifiers();
      if (Modifier.isStatic(modifiers)) {
        continue;
      }
      Column column = this.convert(field);
      columns.add(column);
    }

    return columns;
  }

  private Column convert(Field field) {
    Column column = new Column();
    column.setOriginal(field);
    column.setKey(field.getName());
    column.setType(field.getType());
    // 针对没有排序的字段的默认设置
    column.setOrder(100);

    ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class);
    if (excelIgnore != null) {
      column.setIgnore(true);
      return column;
    }
    Convert convert = field.getAnnotation(Convert.class);
    this.setColumnBasic(column, field);
    String firstName = column.getFirstName();
    if (StrUtil.isBlank(firstName)) {
      column.setName(new String[] {field.getName()});
    }
    this.setColumnConverters(column, convert);
    this.setColumnCellValueValidateRules(column, convert);
    return column;
  }

  private void setColumnBasic(Column column, Field field) {

    ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
    ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);

    if (ObjectUtil.isNotNull(excelProperty)) {
      column.setName(excelProperty.value());
      // priority: index > order > default sort
      column.setOrder(excelProperty.index() > 0 ? excelProperty.index() : excelProperty.order());
    } else if (ObjectUtil.isNotNull(apiModelProperty)) {
      column.setName(new String[] {apiModelProperty.value()});
      column.setOrder(apiModelProperty.position());
    }
  }

  @SuppressWarnings("rawtypes")
  private void setColumnConverters(Column column, Convert convert) {
    if (convert != null) {
      Class<? extends CellValueConverter> clazz = convert.value();
      if (!clazz.equals(CellValueConverter.class)
          && CellValueConverter.class.isAssignableFrom(clazz)) {
        CellValueConverter converter = ReflectUtil.newInstance(clazz);
        column.setConverter(converter);
      }
    }
  }

  private void setColumnCellValueValidateRules(Column column, Convert convert) {
    if (convert == null) {
      return;
    }
    Class<? extends CellValueValidateRule>[] validates = convert.validates();
    if (ArrayUtil.isNotEmpty(validates)) {
      for (Class<? extends CellValueValidateRule> validate : validates) {
        CellValueValidateRule rule = ReflectUtil.newInstance(validate);
        column.addCellValueValidateRules(rule);
      }
    }
    String regexStr = convert.regexStr();
    if (StrUtil.isNotBlank(regexStr)) {
      CellValueValidateRule regexRule =
          (col, value) -> {
            // 支持正则表达式的验证类
            Pattern pattern = Pattern.compile(regexStr);

            if (value == null) {
              return;
            }
            Assert.isTrue(
                pattern.matcher(String.valueOf(value)).matches(),
                "regular expression: {}, {} -> validation data: {}, failed",
                regexStr,
                col.getKey(),
                value);
          };
      column.addCellValueValidateRules(regexRule);
    }
  }
}
